using EasyXaf.LowCode.RulesEngineEditors.Models;
using EasyXaf.LowCode.RulesEngineEditors.UndoManagers;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Newtonsoft.Json;

namespace EasyXaf.LowCode.RulesEngineEditors;

public sealed partial class RulesEngineRenderer : IAsyncDisposable
{
    private string WorkflowEleId { get; } = $"id-{Guid.NewGuid()}";

    private RulesEngineToolbar RulesEngineToolbar { get; set; }

    private IJSObjectReference JsModule { get; set; }

    private DotNetObjectReference<RulesEngineRenderer> DotNetObjectRef { get; set; }

    private IUndoManager UndoManager { get; } = new UndoManager();

    private WorkflowObject Workflow { get; set; }

    [Parameter]
    public RulesEngineModel Model { get; set; }

    [Inject]
    private IJSRuntime JSRuntime { get; set; }

    private async Task RulesChangedAsync()
    {
        var json = JsonConvert.SerializeObject(Workflow.ToWorkflow());
        Model.Value = json;
        await Model.ValueChanged.InvokeAsync(json);
    }

    protected override void OnInitialized()
    {
        base.OnInitialized();

        RulesEngineWorkflow rulesEngineWorkflow;

        if (!string.IsNullOrWhiteSpace(Model.Value))
        {
            rulesEngineWorkflow = JsonConvert.DeserializeObject<RulesEngineWorkflow>(Model.Value);
        }
        else
        {
            rulesEngineWorkflow = new RulesEngineWorkflow();
        }

        Workflow = WorkflowObject.FromWorkflow(rulesEngineWorkflow);
        Workflow.UndoManager = UndoManager;
        Workflow.Validate();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (firstRender)
        {
            var jsModuleFile = "./_content/EasyXaf.LowCode.RulesEngineEditors/RulesEngineRenderer.razor.js";
            JsModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", jsModuleFile);
            DotNetObjectRef = DotNetObjectReference.Create(this);
            await JsModule.InvokeVoidAsync("init", WorkflowEleId, DotNetObjectRef);
            StateHasChanged();
        }
    }

    [JSInvokable]
    public Task SetZoomAsync(double zoom)
    {
        RulesEngineToolbar.SetZoom(zoom);
        return Task.CompletedTask;
    }

    public async ValueTask DisposeAsync()
    {
        if (JsModule != null)
        {
            await JsModule.InvokeVoidAsync("dispose", WorkflowEleId);
            await JsModule.DisposeAsync();
            JsModule = null;
        }

        if (DotNetObjectRef != null)
        {
            DotNetObjectRef.Dispose();
            DotNetObjectRef = null;
        }
    }
}